package ru.ifmo.network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author avhaliullin
 */
public class Server implements Runnable {
    private final Logger log = Logger.getLogger(Server.class.getName());
    private final ServerSocket serverSocket;
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    private final FilesProvider filesProvider;

    public Server(FilesProvider filesProvider, int port) throws IOException {
        this.filesProvider = filesProvider;
        this.serverSocket = new ServerSocket(port);
    }

    public void run() {
        while (!Thread.interrupted()) {
            try {
                final Socket socket = serverSocket.accept();
                final DataInputStream inputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                final DataOutputStream outputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
                executor.execute(new Runnable() {
                    public void run() {
                        try {
                            String command = inputStream.readUTF();
                            if ("LIST".equals(command)) {
                                List<String> files = filesProvider.listFiles();
                                outputStream.writeInt(files.size());
                                for (String fileName : files) {
                                    outputStream.writeUTF(fileName);
                                }
                                outputStream.flush();
                            } else if ("GET".equals(command)) {
                                String fileName = inputStream.readUTF();
                                File file = filesProvider.getFile(fileName);
                                if (file == null) {
                                    outputStream.writeLong(-1);
                                    return;
                                }
                                outputStream.writeLong(file.length());
                                BufferedInputStream fileIs = new BufferedInputStream(new FileInputStream(file));
                                int len;
                                byte[] buf = new byte[1024];
                                while ((len = fileIs.read(buf, 0, buf.length)) >= 0) {
                                    outputStream.write(buf, 0, len);
                                }
                                outputStream.flush();

                            } else {
                                log.warning("Bad command: " + (command == null ? "null" : '"' + command + '"'));
                            }
                        } catch (IOException e) {
                            log.log(Level.WARNING, "Some fail", e);
                        } finally {
                            try {
                                socket.close();
                            } catch (IOException e) {
                                //ignore
                            }
                        }
                    }
                });
            } catch (IOException e) {
                log.log(Level.WARNING, "Some fail", e);
            }
        }
    }
}
